import tkinter as tk
from tkinter import filedialog, ttk, scrolledtext
import exifread
from PIL import Image, ImageTk, ImageDraw, ImageFont
import os
import sys

class ExifViewerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Cannice 照片EXIF查看器及水印添加V0.2")
        self.root.geometry("800x600")
        self.root.resizable(True, True)

        # 设置中文字体支持
        self.font_family = ("SimHei", "WenQuanYi Micro Hei", "Heiti TC", "Arial")
        self.font_size = 10

        # 缩放因子，适配不同分辨率
        self.scaling_factor = self.root.tk.call('tk', 'scaling')
        if self.scaling_factor < 1.0:
            self.scaling_factor = 1.0

        # 创建主框架
        self.main_frame = ttk.Frame(self.root, padding=10)
        self.main_frame.pack(fill=tk.BOTH, expand=True)

        # 顶部控制区
        self.control_frame = ttk.Frame(self.main_frame)
        self.control_frame.pack(fill=tk.X, pady=(0, 10))

        # 选择图片按钮
        self.select_btn = ttk.Button(
            self.control_frame,
            text="选择图片",
            command=self.select_image,
            style='TButton'
        )
        self.select_btn.pack(side=tk.LEFT, padx=(0, 10))

        # 添加水印按钮
        self.watermark_btn = ttk.Button(
            self.control_frame,
            text="添加水印",
            command=lambda: self.add_watermark_to_image(self.image_path_var.get()),
            style='TButton'
        )
        self.watermark_btn.pack(side=tk.LEFT, padx=(0, 10))

        # 图片路径显示
        self.image_path_var = tk.StringVar()
        self.image_path_entry = ttk.Entry(
            self.control_frame,
            textvariable=self.image_path_var,
            width=50
        )
        self.image_path_entry.pack(side=tk.LEFT, fill=tk.X, expand=True)

        # 分割线
        ttk.Separator(self.main_frame).pack(fill=tk.X, pady=(0, 10))

        # 创建标签页控件
        self.tab_control = ttk.Notebook(self.main_frame)
        self.tab_control.pack(fill=tk.BOTH, expand=True)

        # EXIF信息标签页
        self.exif_tab = ttk.Frame(self.tab_control)
        self.tab_control.add(self.exif_tab, text="EXIF信息")

        # 图片预览标签页
        self.preview_tab = ttk.Frame(self.tab_control)
        self.tab_control.add(self.preview_tab, text="图片预览")

        # 水印预览标签页
        self.watermark_preview_tab = ttk.Frame(self.tab_control)
        self.tab_control.add(self.watermark_preview_tab, text="水印预览")

        # 创建EXIF信息显示区域
        self.exif_text = scrolledtext.ScrolledText(
            self.exif_tab,
            wrap=tk.WORD,
            font=(self.font_family[0], int(self.font_size * self.scaling_factor))
        )
        self.exif_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

        # 创建图片预览区域
        self.preview_label = ttk.Label(self.preview_tab, text="选择图片后显示预览")
        self.preview_label.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

        # 创建水印预览区域
        self.watermark_preview_label = ttk.Label(self.watermark_preview_tab, text="选择图片后显示水印预览")
        self.watermark_preview_label.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

        # 状态栏
        self.status_var = tk.StringVar()
        self.status_var.set("就绪")
        self.status_bar = ttk.Label(
            self.root,
            textvariable=self.status_var,
            relief=tk.SUNKEN,
            anchor=tk.W
        )
        self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)

    def select_image(self):
        """选择图片文件并解析EXIF信息"""
        file_path = filedialog.askopenfilename(
            filetypes=[
                ("图片文件", "*.jpg *.jpeg *.png *.gif *.bmp *.tiff"),
                ("所有文件", "*.*")
            ]
        )

        if not file_path:
            return

        self.image_path_var.set(file_path)
        self.status_var.set(f"正在解析 {os.path.basename(file_path)} 的EXIF信息...")
        self.root.update_idletasks()

        try:
            # 解析EXIF信息
            exif_data = self.parse_exif(file_path)

            # 显示EXIF信息
            self.display_exif(exif_data)

            # 显示图片预览
            self.display_preview(file_path)

            # 显示水印预览
            self.display_watermark_preview(file_path)

            self.status_var.set(f"已加载 {os.path.basename(file_path)}")
        except Exception as e:
            self.exif_text.delete(1.0, tk.END)
            self.exif_text.insert(tk.END, f"解析EXIF信息时出错: {str(e)}")
            self.status_var.set("解析失败")

    def get_exif_maker(self, file_path):
        """提取图片EXIF信息中的制造商(maker)"""
        with open(file_path, 'rb') as f:
            tags = exifread.process_file(f)
            maker_tag = 'Image Make'
            if maker_tag in tags:
                return str(tags[maker_tag]).strip()
        return None

    def get_exif_model(self, file_path):
        """提取图片EXIF信息中的型号(model)"""
        with open(file_path, 'rb') as f:
            tags = exifread.process_file(f)
            model_tag = 'Image Model'
            if model_tag in tags:
                return str(tags[model_tag]).strip()
        return None

    def get_capture_date(self, file_path):
        """提取图片的拍摄日期"""
        with open(file_path, 'rb') as f:
            tags = exifread.process_file(f)
            # 尝试常见的日期标签
            date_tags = ["EXIF DateTimeOriginal", "EXIF DateTimeDigitized", "Image DateTime"]
            for tag in date_tags:
                if tag in tags:
                    return str(tags[tag])
        return "未知日期"

    def parse_exif(self, file_path):
        """使用exifread库解析图片的EXIF信息"""
        with open(file_path, 'rb') as f:
            tags = exifread.process_file(f)
        return tags

    def add_watermark_to_image(self, file_path):
        """为当前图片添加水印并保存"""
        if not file_path:
            self.status_var.set("请先选择一张图片")
            return

        try:
            # 获取制造商信息
            maker = self.get_exif_maker(file_path)
            if not maker:
                maker = "未知制造商"

            # 获取型号信息
            model = self.get_exif_model(file_path)
            if model:
                maker = f"{maker} {model}"  # 将model添加到maker后面

            # 获取拍摄日期
            capture_date = self.get_capture_date(file_path)

            # 让用户选择保存路径
            output_path = filedialog.asksaveasfilename(
                defaultextension=".jpg",
                filetypes=[
                    ("JPEG图片", "*.jpg"),
                    ("PNG图片", "*.png"),
                    ("所有文件", "*.*")
                ],
                initialfile=f"{os.path.splitext(os.path.basename(file_path))[0]}_watermarked.jpg"
            )

            if not output_path:
                return

            # 添加水印
            with Image.open(file_path).convert("RGBA") as img:
                draw = ImageDraw.Draw(img)
                width, height = img.size

                # 设置水印字体和大小
                font_size = int(min(width, height) * 0.05)  # 图片最小边的5%

                # 尝试加载系统字体，支持中文显示
                try:
                    # 尝试不同系统的常见字体路径
                    font_paths = [
                        "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc",  # Linux
                        "/System/Library/Fonts/PingFang.ttc",  # macOS
                        "C:\\Windows\\Fonts\\simhei.ttf",  # Windows
                        "/usr/share/fonts/truetype/freefont/FreeSans.ttf"  # 通用后备
                    ]
                    font = None
                    for path in font_paths:
                        try:
                            font = ImageFont.truetype(path, font_size)
                            break
                        except:
                            continue
                    if not font:
                        font = ImageFont.load_default()
                except:
                    font = ImageFont.load_default()

                # 计算文本尺寸
                bbox = draw.textbbox((0, 0), maker, font=font)
                text_width = bbox[2] - bbox[0]
                text_height = bbox[3] - bbox[1]

                # 设置行间距
                line_spacing = int(text_height * 0.3)  # 行间距为文本高度的30%

                # 设置水印位置（左下角，带边距）
                margin = int(min(width, height) * 0.02)  # 边距为图片最小边的2%
                x = margin
                # 计算总文本高度（两行文本 + 行间距）
                total_text_height = text_height * 2 + line_spacing
                y = height - total_text_height - margin

                # 添加半透明白色水印（带轻微黑色描边增加可读性）
                # 添加制造商水印（带描边）
                # 描边
                draw.text((x-1, y-1), maker, font=font, fill=(0, 0, 0, 100))
                draw.text((x+1, y-1), maker, font=font, fill=(0, 0, 0, 100))
                draw.text((x-1, y+1), maker, font=font, fill=(0, 0, 0, 100))
                draw.text((x+1, y+1), maker, font=font, fill=(0, 0, 0, 100))
                # 主文本
                draw.text((x, y), maker, font=font, fill=(255, 255, 255, 200))

                # 计算日期文本位置（制造商下方）
                date_y = y + text_height + line_spacing

                # 添加日期水印（带描边）
                # 描边
                draw.text((x-1, date_y-1), capture_date, font=font, fill=(0, 0, 0, 100))
                draw.text((x+1, date_y-1), capture_date, font=font, fill=(0, 0, 0, 100))
                draw.text((x-1, date_y+1), capture_date, font=font, fill=(0, 0, 0, 100))
                draw.text((x+1, date_y+1), capture_date, font=font, fill=(0, 0, 0, 100))
                # 主文本
                draw.text((x, date_y), capture_date, font=font, fill=(255, 255, 255, 200))

                # 转换回RGB模式并保存
                img.convert("RGB").save(output_path, quality=95)

            self.status_var.set(f"水印已添加并保存到: {output_path}")
        except Exception as e:
            self.status_var.set(f"添加水印时出错: {str(e)}")

    def display_exif(self, exif_data):
        """在文本区域显示EXIF信息"""
        self.exif_text.delete(1.0, tk.END)

        if not exif_data:
            self.exif_text.insert(tk.END, "未找到EXIF信息")
            return

        # 分类显示EXIF信息
        self.exif_text.insert(tk.END, "=== 图片基本信息 ===\n")
        for tag in exif_data:
            if tag.startswith('Image '):
                self.exif_text.insert(tk.END, f"{tag}: {exif_data[tag]}\n")

        self.exif_text.insert(tk.END, "\n=== 相机信息 ===\n")
        for tag in exif_data:
            if tag.startswith('EXIF '):
                self.exif_text.insert(tk.END, f"{tag}: {exif_data[tag]}\n")

        self.exif_text.insert(tk.END, "\n=== GPS信息 ===\n")
        has_gps = False
        for tag in exif_data:
            if tag.startswith('GPS '):
                self.exif_text.insert(tk.END, f"{tag}: {exif_data[tag]}\n")
                has_gps = True
        if not has_gps:
            self.exif_text.insert(tk.END, "未找到GPS信息\n")

    def display_preview(self, file_path):
        """显示图片预览"""
        try:
            # 打开图片并调整大小以适应预览区域
            image = Image.open(file_path)
            width, height = image.size

            # 计算预览尺寸，保持宽高比
            max_width = 700
            max_height = 400
            ratio = min(max_width/width, max_height/height)
            new_width = int(width * ratio)
            new_height = int(height * ratio)

            # 调整图片大小
            image = image.resize((new_width, new_height), Image.LANCZOS)

            # 转换为Tkinter可用的图片格式
            photo = ImageTk.PhotoImage(image)

            # 更新预览标签
            self.preview_label.config(image=photo)
            self.preview_label.image = photo  # 保持引用避免垃圾回收
        except Exception as e:
            self.preview_label.config(text=f"无法显示预览: {str(e)}")

    def display_watermark_preview(self, file_path):
        """显示水印预览"""
        try:
            # 获取制造商信息
            maker = self.get_exif_maker(file_path)
            if not maker:
                maker = "未知制造商"

            # 获取型号信息
            model = self.get_exif_model(file_path)
            if model:
                maker = f"{maker} {model}"  # 将model添加到maker后面

            # 获取拍摄日期
            capture_date = self.get_capture_date(file_path)

            # 打开图片并调整大小以适应预览区域
            image = Image.open(file_path).convert("RGBA")
            width, height = image.size

            # 计算预览尺寸，保持宽高比
            max_width = 700
            max_height = 400
            ratio = min(max_width/width, max_height/height)
            new_width = int(width * ratio)
            new_height = int(height * ratio)

            # 调整图片大小
            image = image.resize((new_width, new_height), Image.LANCZOS)

            # 添加水印到预览图
            draw = ImageDraw.Draw(image)
            width, height = image.size

            # 设置水印字体和大小
            font_size = int(min(width, height) * 0.05)  # 图片最小边的5%

            # 尝试加载系统字体，支持中文显示
            try:
                # 尝试不同系统的常见字体路径
                font_paths = [
                    "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc",  # Linux
                    "/System/Library/Fonts/PingFang.ttc",  # macOS
                    "C:\\Windows\\Fonts\\simhei.ttf",  # Windows
                    "/usr/share/fonts/truetype/freefont/FreeSans.ttf"  # 通用后备
                ]
                font = None
                for path in font_paths:
                    try:
                        font = ImageFont.truetype(path, font_size)
                        break
                    except:
                        continue
                if not font:
                    font = ImageFont.load_default()
            except:
                font = ImageFont.load_default()

            # 计算文本尺寸
            bbox = draw.textbbox((0, 0), maker, font=font)
            text_width = bbox[2] - bbox[0]
            text_height = bbox[3] - bbox[1]

            # 设置行间距
            line_spacing = int(text_height * 0.3)  # 行间距为文本高度的30%

            # 设置水印位置（左下角，带边距）
            margin = int(min(width, height) * 0.02)  # 边距为图片最小边的2%
            x = margin
            # 计算总文本高度（两行文本 + 行间距）
            total_text_height = text_height * 2 + line_spacing
            y = height - total_text_height - margin

            # 添加半透明白色水印（带轻微黑色描边增加可读性）
            # 添加制造商水印（带描边）
            # 描边
            draw.text((x-1, y-1), maker, font=font, fill=(0, 0, 0, 100))
            draw.text((x+1, y-1), maker, font=font, fill=(0, 0, 0, 100))
            draw.text((x-1, y+1), maker, font=font, fill=(0, 0, 0, 100))
            draw.text((x+1, y+1), maker, font=font, fill=(0, 0, 0, 100))
            # 主文本
            draw.text((x, y), maker, font=font, fill=(255, 255, 255, 200))

            # 计算日期文本位置（制造商下方）
            date_y = y + text_height + line_spacing

            # 添加日期水印（带描边）
            # 描边
            draw.text((x-1, date_y-1), capture_date, font=font, fill=(0, 0, 0, 100))
            draw.text((x+1, date_y-1), capture_date, font=font, fill=(0, 0, 0, 100))
            draw.text((x-1, date_y+1), capture_date, font=font, fill=(0, 0, 0, 100))
            draw.text((x+1, date_y+1), capture_date, font=font, fill=(0, 0, 0, 100))
            # 主文本
            draw.text((x, date_y), capture_date, font=font, fill=(255, 255, 255, 200))

            # 转换为Tkinter可用的图片格式
            photo = ImageTk.PhotoImage(image)

            # 更新水印预览标签
            self.watermark_preview_label.config(image=photo)
            self.watermark_preview_label.image = photo  # 保持引用避免垃圾回收
        except Exception as e:
            self.watermark_preview_label.config(text=f"无法显示水印预览: {str(e)}")

def main():
    # 检查是否安装了必要的库
    try:
        import exifread
    except ImportError:
        print("请安装exifread库: pip install exifread")
        sys.exit(1)

    try:
        from PIL import Image, ImageTk
    except ImportError:
        print("请安装Pillow库: pip install Pillow")
        sys.exit(1)

    # 创建并运行应用
    root = tk.Tk()
    app = ExifViewerApp(root)
    root.mainloop()

if __name__ == '__main__':
    main()